using namespace std ;

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include "gsupplyLinkProblem.h"
#include "gsupplyLinkTransporter.h"

void GSupplyLinkProblem::setDimension(int d) {
    this->np = d ;
    this->jobData.resize(d) ;
}


/**
 *
 */
void GSupplyLinkProblem::open(string str, int node) {
    if (!node) cout << "GSupplyLinkProblem::open()... " << str << endl ;

    // le constructeur de ifstream permet d'ouvrir un fichier en lecture
    std::ifstream fichier( str.c_str() , ios_base::in );

    if ( fichier ) // ce test échoue si le fichier n'est pas ouvert
    {
        std::string ligne; // variable contenant chaque ligne lue

        /*
        NBR_PRODUCT:5
        CUSTOMER_HOLDING_COSTS:1;1;1;1;1
        TRANSPORTER:
        TRANSPORTER_CAPACITY:6.0
        TRANSPORTER_DELIVERY_TIMES:50.0
        TRANSPORTER_DELIVERY_COSTS:50.0
        DUE_DATES:1000.0;1010.0;1030.0;1030.0;1045.0;
        VOLUMES:3.0;1.0;5.0;2.0;1.0;
        EOF
        */

        // cette boucle s'arrête dès qu'une erreur de lecture survient
        //while ( std::getline( fichier, ligne ) )
        int encore=1 ;
        while ( encore==1 )
        {
            if (!std::getline( fichier, ligne )) encore = 0 ;

            // Suppression des ":" et ";" et conversion en espaces
            for (int ic=0;ic<ligne.length();++ic) {
                if (ligne[ic]==':' || ligne[ic]==';')
                    ligne[ic] = ' ' ;
            }
            istringstream iss(ligne) ;

            string nom_param ;
            double valeur_param ;

            iss >> nom_param ;

            if (nom_param=="NBR_PRODUCT") {
                int problemdimension ;
                iss >> problemdimension;
                this->setDimension (problemdimension) ;
                if (!node) cout << "np=" << np << endl ;
            }

            if (nom_param=="CUSTOMER_HOLDING_COSTS") {
                if (!node) cout << "customerHoldingCost=" ;
                for (int i0=0; i0<this->np;++i0) {
                    iss >> valeur_param ;
                    this->jobData[i0].setHoldingCost(valeur_param) ;
                    if (!node) cout << valeur_param << ", " ;
                }
                if (!node) cout << endl ;
            }

            if (nom_param=="TRANSPORTER") {
                this->transporters.push_back(GSupplyLinkTransporter()) ;
                if (!node) cout << "transporter created" << endl ;
            }

            if (nom_param=="TRANSPORTER_CAPACITY") {
                iss >> valeur_param ;
                (this->getTransporter(0)).setCapacity(valeur_param) ;
                if (!node) cout << "transporter capacity=" << valeur_param << endl ;
            }

            if (nom_param=="TRANSPORTER_DELIVERY_TIMES") {
                if (!node) cout << "transporter delivery times =" ;
                iss >> valeur_param ;
                (this->getTransporter(0)).setDeliveryTime(valeur_param) ;
                if (!node) cout << valeur_param << " " ;
                if (!node) cout << endl ;
            }

            if (nom_param=="TRANSPORTER_DELIVERY_COSTS") {
                if (!node) cout << "transporter delivery costs =" ;
                iss >> valeur_param ;
                (this->getTransporter(0)).setDeliveryCost(valeur_param) ;
                if (!node) cout << valeur_param << " " ;
                if (!node) cout << endl ;
            }

            // DUE_DATES:1000.0;1010.0;1030.0;1030.0;1045.0;
            if (nom_param=="DUE_DATES") {
                if (!node) cout << "dates dues=" ;
                for (int i=0;i<this->np;++i) {
                    iss >> valeur_param ;
                    this->jobData[i].setDueDate(valeur_param) ;
                    if (!node) cout << valeur_param << " " ;
                }
                if (!node) cout << endl ;
            }

            // VOLUMES:3.0;1.0;5.0;2.0;1.0;
            if (nom_param=="VOLUMES") {
                if (!node) cout << "volumes=" ;
                for (int i=0;i<this->np;++i) {
                    iss >> valeur_param ;
                    this->jobData[i].setSize(valeur_param) ;
                    if (!node) cout << valeur_param << " " ;
                }
                if (!node) cout << endl ;
            }

            // afficher la ligne à l'écran
            //std::cout << ligne << std::endl;
            //std::cout << "nom_param=" << nom_param << " ; valeur_param=" << valeur_param << std::endl ;
        }

        if (!node) cout << "GSupplyLinkProblem::open() end\n" << endl ;
    }
    else {
        if (!node) cout << endl << "ERROR file does not exist : " << str << endl << endl ;
        assert(0) ;
    }

    // Sort the due dates in increasing order
    this->jobPermutation.resize(this->getNP()) ;
    for (int i=0;i<this->getNP();++i)
        this->jobPermutation[i] = i ;

    // Sort the jobs in increasing due dates
    for (int i=0;i<this->getNP();i++) {
        int iminduedate = -1 ;
        double minduedate = this->getJobDueDate(i) ;
        for (int j=i+1;j<this->getNP();j++) {
            if (this->getJobDueDate(j)<minduedate) {
                minduedate = this->getJobDueDate(j) ;
                iminduedate = j ;
            }
        }
        if (iminduedate>=0) {
            int itemp = this->jobPermutation[i] ;
            this->jobPermutation[i] = this->jobPermutation[iminduedate] ;
            this->jobPermutation[iminduedate] = itemp ;

            GJobData jobdatatemp = this->jobData[i] ;
            this->jobData[i] = this->jobData[iminduedate] ;
            this->jobData[iminduedate] = jobdatatemp ;
        }
    }

    if (!node) cout << "GSupplyLinkProblem::open() terminated" << endl ;
}

/**
 * Translate the best solution obtained with the jobs ordered in the increasing order of due dates
 * in a solution for the initial problem.
 *
 * @param bestSolutionDueDateOrdered
 * @return
 */
GSupplyLinkSolution GSupplyLinkProblem::getBestSolutionFromBestSolutionDueDateOrdered(GSupplyLinkSolution& bestSolutionDueDateOrdered) {
    GSupplyLinkSolution bestsol (bestSolutionDueDateOrdered) ;
    vector<GJobVariable> newProcessingSchedule(this->np) ;
    for (int i=0;i<this->np;++i) {
        bestsol.setJobVariable(jobPermutation[i], bestSolutionDueDateOrdered.getJobVariable(i)) ;
    }
    return bestsol;

}

/**
 *
 */
ostream& operator<< (ostream& o, const GSupplyLinkProblem& sol) {
    /*
        return "GSupplyLinkProblem [n=" + n + ", transp=" + transporters + "\n" +
		"jobData=" + Arrays.toString(jobData) + "]";
    */
    o << "GSupplyLinkProblem[n=" << sol.np << ", transp=..."  ;
    o << ", jobData=[" ;
    for (int job=0;job<sol.np;++job) {
        double dd = sol.getJobDueDate(job) ;
        o << "GJobData [dueDate=" << dd << ", " ;
        o << "holdingCost=" << sol.getJobHoldingCost(job) << ", " ;
        o << "size=" << sol.getJobSize(job)<<"]" ;
        if (job<sol.np-1) o << ", " ;
    }
    o << "]]" ;

    return o ;
}




